package com.varian.task.core;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ClassUtil;
import com.varian.task.model.BaseTaskModel;
import com.varian.tool.exception.ServerException;
import lombok.SneakyThrows;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author ben
 * @since 2024/11/22
 */
public class MethodTaskHandler implements ITaskHandler {

    private final String taskName;
    private final Object target;
    private final Method taskMethod;
    private final Method initMethod;
    private final Method destroyMethod;
    private final Map<Integer, TaskThreadPool> taskThreadPoolMap;

    public MethodTaskHandler(String taskName, Object target, Method taskMethod, Method initMethod, Method destroyMethod) {
        Assert.isFalse(taskMethod.getParameterCount() > 1, () -> ServerException.of("task method [{}] 参数个数不能大于1", taskName));
        this.taskName = taskName;
        this.target = target;
        this.taskMethod = taskMethod;
        this.initMethod = initMethod;
        this.destroyMethod = destroyMethod;
        this.taskThreadPoolMap = MapUtil.newConcurrentHashMap();
    }

    @Override
    public String getTaskCode() {
        return taskName;
    }

    @SneakyThrows
    @Override
    public void execute(BaseTaskModel taskModel) {
        TaskThreadPool taskThreadPool;
        if (taskThreadPoolMap.containsKey(taskModel.getExecuteBlockStrategy())) {
            taskThreadPool = taskThreadPoolMap.get(taskModel.getExecuteBlockStrategy());
        } else {
            taskThreadPool = new TaskThreadPool(taskModel.getExecuteBlockStrategy());
            taskThreadPoolMap.put(taskModel.getExecuteBlockStrategy(), taskThreadPool);
        }
        try {
            taskThreadPool.submit(() -> doInvoke(taskModel)).get(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            throw new InterruptedException("任务意外中断");
        } catch (TimeoutException e) {
            throw new TimeoutException("任务执行超时");
        }
    }

    @SneakyThrows
    private void doInvoke(BaseTaskModel taskModel) {
        try {
            // 判断是否为基本类型，如果是，则直接赋值
            Class<?> parameterType = taskMethod.getParameterTypes()[0];
            Object taskParam = taskModel.getTaskParam();
            if (!ClassUtil.isSimpleValueType(parameterType)) {
                taskParam = BeanUtil.toBean(taskModel.getTaskParam(), parameterType);
            }
            taskMethod.invoke(target, taskParam);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    @Override
    public void init() throws Exception {
        if (initMethod != null) {
            initMethod.invoke(target);
        }
    }

    @Override
    public void destroy() throws Exception {
        if (destroyMethod != null) {
            destroyMethod.invoke(target);
        }
    }
}
